<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>ESP32-CAM 流媒体</title>
</head>
<body>
  <h2>实时视频流</h2>
  <img id="video" style="width:320px;height:240px;" />

  <h3>控制面板</h3>
  <form id="controlForm">
    <div>
      <label>
        <input type="radio" name="action" value="start" checked> 开始传输
      </label>
      <label>
        <input type="radio" name="action" value="stop"> 停止传输
      </label>
      <label>
        <input type="radio" name="action" value="fps"> 请求帧率
      </label>
    </div>
    <button type="button" id="sendButton">发送指令</button>
  </form>

  <div id="messageArea" style="margin-top: 10px; padding: 10px; border: 1px solid #ccc; background-color: #f9f9f9;">
    <h4>消息日志:</h4>
    <div id="messageLog" style="height: 100px; overflow-y: auto;"></div>
  </div>

  <script>
    // WebSocket连接配置
    const wsUrl = "ws://192.168.3.181:8282";
    const ws = new WebSocket(wsUrl);
    const img = document.getElementById("video");
    let heartbeatInterval = null;
    window.reconnectAttempts = 0;
    const maxReconnectAttempts = 5;
    const reconnectDelay = 3000; // 3秒重连延迟

    // 设置WebSocket二进制类型为arraybuffer，用于接收图像数据
    //ws.binaryType = "arraybuffer";

    // 连接成功时触发
    ws.onopen = function(event) {
      console.log("WebSocket连接已建立");
      window.reconnectAttempts = 0; // 重置重连尝试次数

      // 启动心跳机制，每30秒发送一次心跳
      startHeartbeat();

      // 可选：发送初始化消息
      ws.send(JSON.stringify({ type: "user_init", data:[] }));
    };

    // 接收到消息时触发
    ws.onmessage = function(event) {
        console.log("收到消息:", event);
      // 处理文本数据（JSON格式）
        try {
          const data = JSON.parse(event.data);
          console.log("收到文本消息:", data);
        if (data.type === 'video') {
          // 拼接成 Data URL
          img.src = "data:image/jpeg;base64," + data.data;
        } else if (data.type === "status") {
          // 处理状态更新消息
          console.log("服务器状态:", data.data);
        } else if (data.type === "command") {
          // 处理服务器下发的命令
            console.log("服务器命令:", data.data);
          }
        } catch (e) {
          console.error("解析JSON消息失败:", e);
        }
    };

    // 连接关闭时触发
    ws.onclose = function(event) {
      console.log("WebSocket连接已关闭，代码:", event.code, "原因:", event.reason);
      stopHeartbeat();

      // 如果是异常关闭，尝试重新连接
      if (event.code !== 1000) { // 1000表示正常关闭
        attemptReconnect();
      }
    };

    // 发生错误时触发
    ws.onerror = function(error) {
      console.error("WebSocket错误:", error);
      stopHeartbeat();
    };

    // 启动心跳机制
    function startHeartbeat() {
      // 清除可能存在的旧心跳
      stopHeartbeat();

      // 每30秒发送一次心跳
      heartbeatInterval = setInterval(() => {
        if (ws.readyState === WebSocket.OPEN) {
          ws.send(JSON.stringify({ type: "ping", data:[] }));
          console.log("心跳已发送");
        }
      }, 5000);
    }

    // 停止心跳机制
    function stopHeartbeat() {
      if (heartbeatInterval) {
        clearInterval(heartbeatInterval);
        heartbeatInterval = null;
      }
    }

    // 尝试重新连接
    function attemptReconnect() {
      if (window.reconnectAttempts < maxReconnectAttempts) {
        window.reconnectAttempts++;
        console.log(`尝试重新连接 (${window.reconnectAttempts}/${maxReconnectAttempts})...`);

        // 延迟后尝试重新连接
        setTimeout(() => {
          console.log("正在重新连接到服务器...");
          const newWs = new WebSocket(wsUrl);

          // 复制事件处理器
          newWs.binaryType = "arraybuffer";
          newWs.onopen = function(event) {
            console.log("新WebSocket连接已建立");
            window.reconnectAttempts = 0;
            startHeartbeat();
            newWs.send(JSON.stringify({ type: "init", message: "客户端已重新连接" }));
          };
          newWs.onmessage = function(event) {
            // 处理二进制数据（图像）
            if (event.data instanceof ArrayBuffer) {
              const blob = new Blob([event.data], { type: "image/jpeg" });
              img.src = URL.createObjectURL(blob);
            }
            // 处理文本数据（JSON格式）
            else if (typeof event.data === "string") {
              try {
                const data = JSON.parse(event.data);
                console.log("收到文本消息:", data);
              } catch (e) {
                console.error("解析JSON消息失败:", e);
              }
            }
          };
          newWs.onclose = function(event) {
            console.log("WebSocket连接已关闭，代码:", event.code, "原因:", event.reason);
            stopHeartbeat();

            // 如果是异常关闭，尝试重新连接
            if (event.code !== 1000) { // 1000表示正常关闭
              attemptReconnect();
            }
          };
          newWs.onerror = function(error) {
            console.error("WebSocket错误:", error);
            stopHeartbeat();
          };

          // 更新WebSocket引用
          window.currentWebSocket = newWs;

          // 添加到消息日志
          addMessageLog("已重新连接到服务器");
        }, reconnectDelay);
      } else {
        console.error("达到最大重连尝试次数，停止重连");
        addMessageLog("连接失败，达到最大重连尝试次数");
        // 可以在这里添加用户提示或其他逻辑
      }
    }

    // 发送消息到服务器的函数
    function sendMessage(message) {
      const currentWs = window.currentWebSocket || ws;
      if (currentWs.readyState === WebSocket.OPEN) {
        if (typeof message === "object") {
          currentWs.send(JSON.stringify(message));
        } else {
          currentWs.send(message);
        }
        console.log("消息已发送:", message);
      } else {
        console.error("WebSocket未连接，无法发送消息");
      }
    }

    // 页面关闭前清理资源
    window.addEventListener("beforeunload", () => {
      stopHeartbeat();
      const currentWs = window.currentWebSocket || ws;
      if (currentWs.readyState === WebSocket.OPEN) {
        currentWs.close(1000, "页面关闭");
      }
    });

    // 添加表单事件处理
    document.getElementById("sendButton").addEventListener("click", () => {
      const selectedAction = document.querySelector('input[name="action"]:checked').value;

      // 根据选择的操作类型发送不同的消息
      let message;
      switch(selectedAction) {
        case "start":
          message = { type: "user_send_device", action: "start", message: "开始视频传输" };
          break;
        case "stop":
          message = { type: "user_send_device", action: "stop", message: "停止视频传输" };
          break;
        case "fps":
          message = { type: "user_send_device", action: "fps", data: 2, message: "请求帧率" };
          break;
        default:
          message = { type: "user_send_device", action: "unknown", message: "未知操作" };
      }

      // 发送消息到服务器
      sendMessage(message);

      // 添加到消息日志
      addMessageLog(`已发送指令: ${message.action} - ${message.message}`);
    });

    // 添加消息日志的函数
    function addMessageLog(message) {
      const messageLog = document.getElementById("messageLog");
      const timestamp = new Date().toLocaleTimeString();
      const logEntry = document.createElement("div");
      logEntry.textContent = `[${timestamp}] ${message}`;
      messageLog.appendChild(logEntry);
      messageLog.scrollTop = messageLog.scrollHeight;
    }
  </script>
</body>
</html>
